﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Sern.Common;

namespace Sern.Abstracts.Common
{
    [DataContract]
    public class SelfHealingKey<TKey>
    {
        [DataMember]
        public long Iteration { get; set; }

        [DataMember]
        public TKey Key { get; set; }

        /// <summary>
        /// TODO: This needs to be converted to objects, because the redundancy keys practically tracks the path taken by an entity. So we need this to be dynamically typed.
        /// </summary>
        [DataMember]
        public Queue<object> RedundancyKeys { get; set; }

    }

    public static class SelfHealingKey
    {
        /// <summary>
        /// Creates a new key from the old key.
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TRedundancyKey"></typeparam>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <param name="newRedundancyKey"></param>
        /// <returns></returns>
        public static SelfHealingKey<TKey> CreateFrom<TKey,TRedundancyKey>(this SelfHealingKey<TKey> oldKey, TKey newKey, TRedundancyKey newRedundancyKey)
        {
            var key = oldKey.DeepClone(); //Need to find a way to clone the old key.
            key.Iteration++; //In order to form proper closure around each loop, the filter/aggregate needs to know which loop it came from, otherwise it might be aggregating from the last loop.
            key.Key = newKey;
            key.RedundancyKeys.Enqueue(newRedundancyKey);
            return key;
        }

        /// <summary>
        /// Creates a new self healing key. A factory so user does not have to instantiate the call on their own.
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TRedundancyKey"></typeparam>
        /// <param name="newKey"></param>
        /// <param name="newRedundancyKey"></param>
        /// <returns></returns>
        public static SelfHealingKey<TKey> CreateNew<TKey,TRedundancyKey>(TKey newKey, TRedundancyKey newRedundancyKey)
        {

            return new SelfHealingKey<TKey>()
                {
                    Iteration = 0,
                    Key = newKey,
                    RedundancyKeys = new Queue<object>(new object[] {newRedundancyKey})
                };
        }
    }
}
